package config

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/redis/go-redis/v9"
	"github.com/spf13/viper"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type config struct {
	Server struct {
		Port int64  `yaml:"port"`
		Host string `yaml:"host"`
	} `yaml:"server"`

	Mysql struct {
		DSN  string `yaml:"dsn"`
		Host string `yaml:"host"`
		Port int64  `yaml:"port"`
		User string `yaml:"user"`
		Pass string `yaml:"pass"`
		Name string `yaml:"name"`
	} `yaml:"mysql"`

	Redis struct {
		Addr     string `yaml:"addr"`
		Password string `yaml:"password"`
		DB       int    `yaml:"db"`
	} `yaml:"redis"`

	JWT struct {
		SecretKey string `yaml:"secretKey"`
	} `yaml:"jwt"`
}

var fileLock sync.Mutex
var Config *config

func Load() error {
	fileLock.Lock()
	defer fileLock.Unlock()

	viper.SetConfigName("config")
	viper.SetConfigType("yaml")
	viper.AddConfigPath("./")

	if err := viper.ReadInConfig(); err != nil {
		return err
	}

	var config config
	if err := viper.Unmarshal(&config); err != nil {
		return err
	}

	Config = &config
	return nil
}

func GetConfig() *config {
	return Config
}

var DBProvider *gorm.DB
var SlaveDBProvider *gorm.DB
var Client *redis.Client

func InitDB() error {
	c := GetConfig()
	dsn := fmt.Sprintf(c.Mysql.DSN, c.Mysql.User, c.Mysql.Pass, c.Mysql.Host, c.Mysql.Port, c.Mysql.Name)
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		return err
	}

	sqlDB, err := db.DB()
	if err != nil {
		return err
	}

	sqlDB.SetMaxIdleConns(20)
	sqlDB.SetMaxOpenConns(100)
	sqlDB.SetConnMaxLifetime(time.Hour)

	DBProvider = db
	return nil
}

func GetProvider() *gorm.DB {
	return DBProvider
}

func InitRedis() error {
	c := GetConfig()
	Client = redis.NewClient(&redis.Options{
		Addr:     c.Redis.Addr,     // redis地址
		Password: c.Redis.Password, // 密码
		DB:       c.Redis.DB,       // 使用默认数据库
	})
	err := Client.Ping(context.Background()).Err()
	if err != nil {
		return err
	}
	err = Connect(context.Background(), Client)
	return err
}

func GetRedisClient() *redis.Client {
	return Client
}

type DistributeQueue struct {
	client *redis.Client
}

var queue *DistributeQueue

func Connect(ctx context.Context, client *redis.Client) error {
	queue = &DistributeQueue{}

	queue.client = client

	// 此处为了测试 Redis 的连通性
	_, err := queue.client.Ping(ctx).Result()
	if err != nil {
		return err
	}

	return nil
}
